﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDD.Core {
    using Vector3 = Vector3<float>;
    using Vector4 = Vector4<float>;

    /// <summary>
    /// Lambert-Phongのシェーダーで使用される係数を持つマテリアル
    /// </summary>
    /// <remarks>
    /// 一般的なLambert-Phongモデルで使用される情報を保存するためのクラス
    /// </remarks>
    public class PhongMaterial : Material {

        #region Field
        Vector3 ambient;
        Vector4 diffuse;
        Vector4 specular;
        #endregion

        #region Constructor
        /// <summary>
        /// コンストラクター
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        ///   <item><see cref="Ambient"/>=(1,1,1)</item>
        ///   <item><see cref="Diffuse"/>=(1,1,1,1)</item>
        ///   <item><see cref="Specular"/>=(1,1,1,10)</item>
        /// </list>
        /// です｡
        /// </remarks>
        public PhongMaterial () {
            this.ambient = new Vector3 (1,1,1);
            this.diffuse = new Vector4 (1, 1, 1, 1);
            this.specular = new Vector4 (1, 1, 1, 10);
        }
        #endregion

        #region Property
        /// <summary>
        /// 環境係数
        /// </summary>
        /// <remarks>
        /// R,G,Bの順番です｡
        /// </remarks>
        public Vector3 Ambient {
            get { return ambient; }
        }

        /// <summary>
        /// 拡散係数
        /// </summary>
        /// <remarks>
        /// R,G,B,Aの順番です｡
        /// この並びはGLSL側にエクスポートした時に一致します｡
        /// </remarks>
        public Vector4 Diffuse {
            get { return diffuse; }
        }


        /// <summary>
        /// 鏡面係数
        /// </summary>
        /// <remarks>
        /// R,G,B,Expの順番です｡
        /// </remarks>
        public Vector4 Specular {
            get { return specular; }
        }

        /// <summary>
        /// このオブジェクトが参照する全DDDオブジェクトを列挙する列挙子
        /// </summary>
        /// <remarks>
        /// 参照にnullは含まれません。同一のオブジェクトが複数出現する可能性があります。
        /// </remarks>
        public override IEnumerable<Object> References {
            get {
                return base.References;
            }
        }

        #endregion

        #region Method
        /// <summary>
        /// 環境係数をセットします
        /// </summary>
        /// <param name="r">R成分[0,1]</param>
        /// <param name="g">G成分[0,1]</param>
        /// <param name="b">B成分[0,1]</param>
        public void SetAmbient (float r, float g, float b) {
            if (r < 0 || r > 1) {
                throw new ArgumentException ("R is invalid");
            }
            if (g < 0 || g > 1) {
                throw new ArgumentException ("G is invalid");
            }
            if (b < 0 || b > 1) {
                throw new ArgumentException ("B is invalid");
            }

            this.ambient = new Vector3 (r, g, b);
        }

        /// <summary>
        /// 拡散係数をセットします
        /// </summary>
        /// <param name="r">R成分[0,1]</param>
        /// <param name="g">G成分[0,1]</param>
        /// <param name="b">B成分[0,1]</param>
        /// <param name="a">A成分[0,1]</param>
        public void SetDiffuse (float r, float g, float b, float a) {
            if (r < 0 || r > 1) {
                throw new ArgumentException ("R is invalid");
            }
            if (g < 0 || g > 1) {
                throw new ArgumentException ("G is invalid");
            }
            if (b < 0 || b > 1) {
                throw new ArgumentException ("B is invalid");
            }
            if (a < 0 || a > 1) {
                throw new ArgumentException ("A is invalid");
            }
        
            this.diffuse = new Vector4 (r, g, b, a);
        }

        /// <summary>
        /// 鏡面係数をセットします
        /// </summary>
        /// <param name="r">R成分[0,1]</param>
        /// <param name="g">G成分[0,1]</param>
        /// <param name="b">B成分[0,1]</param>
        /// <param name="exp">Exp成分[0,128]</param>
        public void SetSpecular (float r, float g, float b, float exp) {
            if (r < 0 || r > 1) {
                throw new ArgumentException ("R is invalid");
            }
            if (g < 0 || g > 1) {
                throw new ArgumentException ("G is invalid");
            }
            if (b < 0 || b > 1) {
                throw new ArgumentException ("B is invalid");
            }
            if (exp < 0 || b > 128) {
                throw new ArgumentException ("Exp is invlid");
            }

            this.specular = new Vector4 (r, g, b, exp);
        }

        /// <summary>
        /// 現在のオブジェクトの状態を表す文字列を返します。
        /// </summary>
        public override string ToString () {
            return string.Format ("");
        }
        #endregion



    }
}
